package com.sky.aspect;


import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component
@Aspect
@Slf4j
public class AutoFillAspect {

    /*
    * 切入点表达式，对包扫描，并限定范围
    * */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void pt(){

    }

    /*
    * 前置通知
    * */
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info("公共字段填充：{}",joinPoint);
//      目标：对指定的增强方法获取参数对象，填充公共字段
//      1.通过joinPoint获取方法签名对象(原始方法)
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//      2.通过方法签名对象获取@AutoFill注解对象
        AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);
//      3.获取@AutoFill注解对象的值，便于后面用insert或update进行处理
        OperationType operationType = autoFill.value();
//      4.joinPoint获取原始方法参数数组
        Object[] args = joinPoint.getArgs();
//      5.判断参数数组是否有效，无效结束
        if(args == null || args.length == 0){
            return;
        }
//      6.获取参数数组下，下标为0的参数对象
        Object obj = args[0];
//      7.准备操作时间和操作人
        LocalDateTime now = LocalDateTime.now();
        Long empId = BaseContext.getCurrentId();

        try {
            //8.判断@AutoFill注解对象的值如果为OperationType.Insert，填充4个字段
            if(operationType == OperationType.INSERT){
                //已知条件：对象obj，方法名字符串
                //获取set封装数据方法语法：obj.getClass().getMethod("方法名字符串",参数类型字节码)
                Method updateUserMethod = obj.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                Method createUserMethod = obj.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method updateTimeMethod = obj.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method createTimeMethod = obj.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                //执行方法反射语法： method.invoke(方法所属的对象,数据值)
                updateUserMethod.invoke(obj,empId);  //employee.setUpdateUser(empId)
                createUserMethod.invoke(obj,empId);
                updateTimeMethod.invoke(obj,now);
                createTimeMethod.invoke(obj,now);

            }else {

                //9.否则，填充2个字段
                Method updateUserMethod = obj.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                Method updateTimeMethod = obj.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                updateUserMethod.invoke(obj,empId);  //employee.setUpdateUser(empId)
                updateTimeMethod.invoke(obj,now);
            }
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("公共字段填充失败：{}",e.getMessage());
        }
    }
}
